#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <functional>
#include <signal.h>
#include "logMessage.hpp"
#include "protocal.hpp"
#define SEP " "
#define SEP_LEN strlen(SEP)
using namespace std;
static const uint16_t gport = 8080;
static const int gbacklog = 5;
string suffixToDesc(const string &suffix)
{
    string ct = "Content-Type: ";
    if(suffix ==".html")
    ct += "text/html";
    else if(suffix == ".jpg")
    ct += "application/x-jpg";
    ct += "\r\n";
    return ct;
}
typedef function<bool(const httpRequest &req, httpRespons &res)> func_t;
bool Get(const httpRequest &req, httpRespons &res)
{
    cout<<"----------------http start-----------------"<<endl;;
    cout<<req.inbuffer<<endl;
    cout<<"----------------http end-------------------"<<endl;;
    cout<< "method :"<<req.method<<endl;
    cout<< "url :"<<req.url<<endl;
    cout<< "httpVersion :"<<req.httpVersion<<endl;
    cout<< "path :"<<req.path<<endl;
    cout<< "suffix :"<<req.suffix<<endl;
    cout<< "size :"<<req.size<<endl;
    string respline = "HTTP/1.1 200 OK\r\n";
    string block = "\r\n";
    // string body = "<html lang=\"en\"><head><title>for test</title><h1>hello world<h1></head><body><p>我是风吹饼</body></html>";
    string respHeader = suffixToDesc(req.suffix);
    string body;
    body.resize(req.size+1);
    if(!Unit::Readfile(req.path,(char*)body.c_str(),req.size))
    {
        //进入404
        Unit::Readfile(html_404,(char*)body.c_str(),req.size);
    }
    res.outbuffer = respline + block + body;
    return true;
}   
void HanderEntery(int sock,func_t func)
{
    char buffer[4096];
    httpRequest req;
    httpRespons res;
    ssize_t n = recv(sock,buffer,sizeof buffer,0);
    if(n>0)
    {
        buffer[n] = 0;
        req.inbuffer = buffer;
        req.parse();
        func(req,res);
        send(sock,res.outbuffer.c_str(),res.outbuffer.size(),0);
    }
    
}
class httpServer
{

public:
    httpServer(const uint16_t &port = gport) : _port(port)
    {}
    ~httpServer()
    {}
    void Init()
    {
        // 创建套接字
        _socketfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_socketfd < 0)
        {
            logMessage(ERROR, "socket create error errno : %d",errno);
            exit(2);
        }
        logMessage(NORMAL,"socket success");
        // bind
        struct sockaddr_in lohttp;
        lohttp.sin_family = AF_INET;
        lohttp.sin_port = htons(_port);
        lohttp.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_socketfd, (struct sockaddr *)&lohttp, sizeof(lohttp));
        if (n < 0)
        {
            logMessage(ERROR, "bind error  errno : %d",errno);
            cerr << strerror(errno) << endl;
            exit(2);
        }
        logMessage(NORMAL, "bind success");
        // lisen
        _listenfd = listen(_socketfd, gbacklog);
        if (_listenfd < 0)
        {
            logMessage(ERROR, "listen error errno : %d",errno);
            exit(2);
        }
        logMessage(NORMAL, "listen success");
    }
    
    void start()
    {
        //对子进程返回信号无视
        //signal(SIGCHLD,SIG_IGN);
        while (1)
        {
            // 建立新连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = accept(_socketfd, (struct sockaddr *)&peer, &len);
            // 未来通信就使用sock，后续为文件操作
            if (sock < 0)
            {
                logMessage(ERROR, "accept error  errno : %d",errno);
                exit(2);
            }
            cout << sock << endl;
            logMessage(NORMAL, "accept success");
            // Verson 2多进程版
            pid_t id = fork();
            if (id == 0)
            {
                close(_listenfd); // 子进程不需要监听，防止误操作
                if(fork()>0)exit(0);//创建孙子进程进行后续操作，子进程直接退出，孙子进程完成任务会被当作孤儿进程回收
                HanderEntery(sock,Get);
                close(sock);
                exit(0);
            }
            //father
            close(sock);  
        }
    }

private:
    int _socketfd;
    int _listenfd;
    uint16_t _port;
};
